package com.newhis.utils;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.newhis.properties.MinioProperties;
import com.newhis.thirdpart.CustomMinioClient;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.ListPartsResponse;
import io.minio.MinioClient;
import io.minio.http.Method;
import io.minio.messages.Part;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
public class FileUtils {
    private static final Logger log = LoggerFactory.getLogger(FileUtils.class);
    private static MinioProperties minioProperties = SpringUtils.getBean(MinioProperties.class);

    /**
     * 获取文件上传地址
     * @param filePath
     * @return
     */
    public static String getUploadUrl(String filePath){
        try {
            MinioClient minioClient = SpringUtils.getBean(MinioClient.class);
            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs
                    .builder()
                    .method(Method.PUT)
                    .bucket(minioProperties.getBucket())
                    .object(filePath)
                    .expiry(minioProperties.getUrlExpireTime(), TimeUnit.MINUTES).build());
        } catch (Exception e) {
            log.error("获取文件上传地址异常", e);
            return "";
        }
    }

    public static Map<String, Object> initMultiPartUpload(String objectName, int partCount, String contentType){
        Map<String, Object> result = new HashMap<>(16);
        try {
            if (StringUtils.isBlank(contentType)){
                contentType = "application/octet-stream";
            }

            CustomMinioClient minioClient = SpringUtils.getBean(CustomMinioClient.class);
            //获取上传id
            Multimap<String, String> headers = HashMultimap.create();
            headers.put("Content-Type", contentType);
            String uploadId = minioClient.initMultiPartUpload(minioProperties.getBucket(), null, objectName, headers, null);
            result.put("uploadId", uploadId);
            //分片上传
            List<String> partList = new ArrayList<>();
            //分片号
            Map<String, String> reqParams = new HashMap<>(16);
            reqParams.put("uploadId", uploadId);
            for (int i=1;i<=partCount;i++){
                reqParams.put("partNumber", String.valueOf(i));
                String uploadUrl = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs
                        .builder()
                        .method(Method.PUT)
                        .bucket(minioProperties.getBucket())
                        .object(objectName)
                        .expiry(minioProperties.getUrlExpireTime(), TimeUnit.MINUTES)
                        .extraHeaders(headers)
                        .extraQueryParams(reqParams)
                        .build());
                partList.add(uploadUrl);
            }
            result.put("uploadUrls", partList);
        } catch (Exception e) {
            log.error("文件分片上传异常", e);
        }
        return result;
    }

    /**
     * 文件上传分片合并
     * @param objectName
     * @param uploadId
     * @return
     */
    public static boolean mergeMultiPartUpload(String objectName, String uploadId){
        try {
            CustomMinioClient minioClient = SpringUtils.getBean(CustomMinioClient.class);
            Part[] parts = new Part[minioProperties.getMaxParts()];
            ListPartsResponse listPartsResponse = minioClient.listMultiPart(minioProperties.getBucket(), null, objectName, minioProperties.getMaxParts(), 0, uploadId, null, null);
            int partNum = 1;
            for (Part part : listPartsResponse.result().partList()){
                parts[partNum-1] = new Part(partNum, part.etag());
                partNum++;
            }
            minioClient.mergeMultiPartUpload(minioProperties.getBucket(), null, objectName, uploadId, parts, null, null);
        }  catch (Exception e) {
            log.error("文件上传分片合并异常", e);
            return false;
        }
        return true;
    }
}
